Alrighty, now we get to move on to our local script for the SCP 294 GUI.
This should be pretty straightforward, as you've likely interacted with GUI and GUI events in the past.
And if you've been in my previous course, you'll be familiar with GUIs and their events.
This guy in particular is going to be the one that contains the keyboard, as well as the display to
show what the player is typing for their drink.
So if I go ahead and enable visibility here, we're just going to have this on their screen.
And whenever they type something in, we're going to show that text here on this little screen.
So inside of our local script for the GUI, we're just going to need three services.
One is going to be the player service.
We're going to need the sound service so we could get access to the guy.
Sounds.
We're also going to need replicated storage as well, so we can get access to some of those assets in
there.
And then let's go ahead and fill out some variables.
I first want to get access to our drink class.
This is going to be our local drink class that exists on the client.
So we're going to require within replicated storage.
We're going to wait for the SCP 294 assets folder to replicate.
And we're going to require our drink class for the client.
And then we're also going to have a reference to our request drink event.
And we'll have that in replicated storage, same folder, and we'll wait for the request remote function.
We'll have a reference to the guy itself, which is just script dot parent.
We'll have a reference to the local player which is just players dot local player.
And then we'll also have a reference to the local character of this player.
So we can just do player dot character.
Or if the player's character hasn't been added yet, we can do or player dot character added and we'll
wait for this event and this event will return to us the character and store it in our variable.
I want to have a reference to that display text or the output box that is in our guy.
So I'll call this output box and it's inside of our guy.
We're going to wait for the frame to replicate just in case.
We're going to wait for the image label in there.
And inside this image label there is a frame called output or a text label called output.
And that's where we're going to put our text.
And I want to refer to all the buttons that are inside of our GUI.
And we can just do that by doing GUI, dot frame, dot image label.
And we'll get every single child that is in our image label.
So inside of our GUI.
Here we have a bunch of buttons.
In each of these buttons are for all the numbers and all of the letters that we could input into our
drink machine.
So that means we're going to have to connect a function to every single one of these text buttons.
And, you know, take their letter and put that in the output box.
I also want to have a reference to the click sound.
For.
When we click a button on our guy, we can play that click sound so it's in sound service.
We'll wait for the SCP 294 sounds to replicate, wait for the guy folder, and we're going to wait for
the button sound.
And then I'm going to create two variables, one called original walk speed and one called original
jump height.
And we're going to store these in these variables because when the player opens the GUI on their screen,
I want to set the player's walk speed to zero and their jump height to zero.
That way they can't move while they have the GUI open.
And then once they close the GUI, we'll set their walk speed and their jump height back to their original
so we can set this equal to the local character.
I'm going to wait for the humanoid.
And we're going to get the walk speed.
And then we could do the same thing for the local character.
Humanoid dot jump height.
And it should be jump height unless you have a different setting set inside of starter player.
So inside of starter player here there's a section called character jump settings.
Typically before they had it where you had to use a property called jump power.
But I believe now they have changed it to use a default called jump height.
But if you still have this enabled, then instead the value is going to be jump power.
So you'll have to change this to jump power instead of jump height.
But I'm just going to use the default of jump height.
And actually I want to have a reference to the other event as well.
Our comms event.
So replicated storage get our assets folder and we'll wait for the communication remote event to replicate.
And then I'm going to use one variable as our debounce.
And this debounce is going to be for when we request to dispense a drink, we're going to output the
text like dispensing.
And we don't want the player to be able to input any more text into the display.
So we'll make sure to enable a Debounce and then disable it once the player gets their drink.
Now for our GUI, I want to have a few functions.
One function I'll have to close the GUI.
I'm going to have a function for every single button or text button inside of our guy, so I'll just
call it on button clicked.
And then I want to have a function for dispensing the drink.
So we'll call it dispense drink.
And then one last function we'll need is I'm going to call it on child added to backpack.
And this is going to listen for when a child or a tool gets added to the player's backpack.
And if it's a drink cup then we're going to create or get a new drink object for our drink class.
Now some handlers will need of course is going to be for the comms event.
And on client event, we're going to connect a Lambda function to this event.
And again we're going to have an action.
And in fact, the only thing I want to do here on the GUI is I want to listen for when an action is
given called we could do something like if action is equal to enable GUI.
So if I go up to a drink machine and enable the proximity prompt, then the server is going to, you
know, verify some stuff and then tell me to enable the GUI on my end, because the server is the one
that's collecting all of the different drink machines and listening to the proximity prompts inside
of them.
So when the specific action gets requested, we can actually have another function.
We can call it open GUI.
And this will be responsible for opening our GUI.
And what we could do here is we could do GUI dot enabled.
Make sure that's set to true.
It should be set to true by default right here.
But just in case it isn't we're going to set it to true.
We're going to do GUI dot frame, set its visibility equal to true.
Because by default the visibility of our frame is set to false.
And then from this point, we could set the original walk speed equal to the local character.
That humanoid dot walk speed.
Same thing with the jump height.
And since the guy is opening on our screen, we want to freeze the player in place.
And the easy way to do that would be to just to access the local player and set the humanoid dot walk
speed property equal to zero, along with the jump height.
And this will stop the player from being able to move around.
So we can call this function right here.
When the server tells us to open a GUI on our screen.
Otherwise, the next thing I'm going to do in this section is I'm going to loop through every single
button that is inside of that buttons table we created.
So for every single thing that exists in that table, which will include all of the children of our
image label.
So all of these things, we want to first verify a few things.
First if the string dot length.
Of this button dot name.
If it's greater than one.
Then we're just going to continue looping, because we only want to care about the specific buttons
that have a name that's only one character long.
We don't want to worry about this.
We don't want to worry about this or any of these other ones.
So if the length of the name of this button is greater than one, then we're just going to continue
looping.
Otherwise, another thing we got to make sure is if this item is a text button.
So if it is not a text button is a text button.
Then we're going to continue looping.
Otherwise, if it's a button and it's one of these ones that have a one character name, then what we
could do is we could do button.
Listen to the event mouse button one up.
And we can connect a lambda function.
And this function is just going to call the on button clicked function.
And in fact we'll pass the button itself to this function.
So in here we can have a parameter for a button.
All right.
The next thing I want to do is I want to listen for each of the buttons that weren't set up by this
for loop, which includes this button, this button, this button and this button.
So we could do GUI dot frame.
Dot image label will wait for.
Let's do the exit button first, just in case it hasn't replicated.
And again we'll listen to mouse button one up.
And we're going to connect a lambda function to this.
First we're going to check if the Debounce is currently active.
So if the Debounce is active then we're just going to return end.
Otherwise, when the player hits the exit button we just want to close our guy.
So that's another thing we could fill out real quick here.
What do we want to do to close the guy?
Well we can set the guy dot frame dot visibility equal to false.
We can set the output box dot text equal to nothing.
That way we can clear any previous message that was in the output box.
And then we could set the local characters dot humanoid, dot walk speed back to the original walk speed
and do the same thing for the jump height.
And we can set Debounce back to false just in case we need to.
We can also go ahead and fill out the on button clicked function as well.
So what do we want to do when one of the buttons on our keyboard gets clicked?
Well, what we could do is of course first check if there is a debounce because we don't want to input
or add anything to our output text label if the Debounce is activated.
However, if it isn't, then we can play that click sound.
And then what we could do is I want to verify that we haven't put too many different, um, characters
into the output text label, so we can actually set a limit to however many text or characters we can
put inside of the output box, because we don't want to put way too many.
We got to we might want to set a limit so we can actually create a constant one.
I'm going to call it Max cars for max characters, and we can set a max character length of something
like 25.
And then I'm also going to actually create a constant for the message when the machine is out of something
or the drink doesn't exist, we can just call it out of range.
Anyways, what we could do inside of our on button click function is we can check.
If stringlength of the output box dot text.
If this is less than max characters, then we can set the output box dot text equal to itself.
And concatenate the string dot upper or get the upper variant of button dot name.
And this is just in case we didn't name one of these particular strings here in upper case.
So if they put n then it'll make sure the output box text isn't greater than 25 characters.
And then it'll concatenate that letter into the output box.
Text.
The next button we could listen to inside of our image label is the space button.
So what we want to happen when we click on our space button.
Well, what we could do is first make sure the debounce is not active.
And now we can basically do the same thing that we did inside of our on button clicked function.
We can make sure that the length of the current output box is text is under 25.
Make sure to play the click sound, and instead of concatenating the name of this button, what we're
going to do is we're just going to concatenate an empty space.
So we'll just have a string with nothing inside of it.
The next one we could do is inside of our frames image label.
We'll wait for the backspace button.
And what do we want to do when this is pressed?
Well what we could do for this one is basically do the exact same things here.
Make sure the debounce isn't active, play the sound, and instead, since we're backspacing or removing
a character from our output box text, we can use the string dot sub function to get a substring of
output box dot text.
And the length is going to be from the first index of our string to the string dot length.
Output box dot text minus one.
So basically we're getting all of the characters from the first index all the way to the second to last
index.
So if we typed in something like hello and we hit backspace, then we'll just get hell.
If we hit backspace again then we'll just get hell and so on.
The next button we need to listen to of course is our enter button.
So frame dot image label wait for enter.
Mouse button one up.
You could use mouse button click as well.
It doesn't really matter that much.
And inside of this one again we want to verify the exact same thing.
Make sure the debounce is not active.
Otherwise, if the Debounce isn't active, this is where we're going to set it to true, because when
the player hits enter, we want to check if this drink they inputted exists, and if it does, we want
to dispense that drink out, and then we'll enable the debounce so we won't be able to manipulate the
output box's text anymore.
So this is where we can create some variables for our, uh, remote function.
So we can have one called success.
And then the remote function we're going to use the check for drink action.
So if we actually go back to our drink class on the server we're going to get returned three different
things.
We're going to get returned, uh, whether or not it was successful, the name or key for the drink,
and then all of the information for the drink.
So we can have one called success.
We can have one called drink name.
And then the properties for this particular drink.
And we're going to use the request drink function and invoke to the server.
We want to check for a drink.
And what drink do we want to check for.
Well we want to check for the one that was inputted inside of our output box.
And the way to do that would be to use string dot lower, because the output box's text is going to
be all in uppercase.
So we want to make sure it's lowercase.
And then we could do output box dot text.
So if we typed in something like uh juice then it'll make it all lowercase.
And then it's going to request for the server to check.
And it's going to look to see if a particular drink has this string.
So for every possible name it's going to check if it has something like that.
Then it's going to return that particular drink to us.
And then we can just easily check if success.
Then we can call the dispense drink function and dispense the drink out.
Otherwise, what we could do is we could set the output box dot text equal to the output message or
out of range, and then we could make the out of range message blink a couple of times if we like.
So we could have a for loop that just loops three times.
Then we could wait for some arbitrary amount of time, like 0.5 seconds.
And then we can do output box dot text transparency.
We can set it to one to make it invisible.
And then we can wait again for another 0.5 seconds and then set it to be visible again.
And once that for loop is finished, we can just set output box dot text back to be nothing again and
we'll set Debounce back to false.
So some events we want to listen to for the player is when a child gets added to the backpack.
So child added we want to connect our on child added to backpack function and make a reference to it.
We also want to listen for when a child gets added to the player itself.
And the thing we want to listen to that gets added to our player is actually the backpack folder.
And this is because since our GUI has the reset on spawn property disabled, this guy is going to be
here forever.
So that means let's say the player dies and their character respawns.
Well, when that happens, their backpack folder actually gets deleted and a new one gets set in its
place.
So that means when that happens, we got to reattach the on child added to backpack event to this new
backpack item.
So that's why we got to listen for when a new child gets added to our player object, which would be
the backpack folder.
So we could make sure that whatever child is being added to our player is the backpack folder.
So if child dot name is not equal to backpack, then we're just going to return because we don't care
about it.
However, if it is the backpack, then we can do the exact same thing here and we'll just replace this
with child.
And then one last thing I want to make sure to do is I want to listen for when a character gets added
to my player.
Get that character in our lambda function.
And then I want to make sure to update our local character property equal to this new character, because
again, the script is going to exist forever because our gene does not get reset when a player dies.
And we want to constantly update the character variable just in case the player dies.
Now we can go ahead and fill out these two functions.
So the first one we could do is on child added to backpack, which should be relatively straightforward.
What we're going to do is we want to make sure that whatever child is being added to the backpack is
a tool.
So if not child is a tool, then we're just going to return.
Uh, another thing we want to check is if this tool has the git attribute, the drink id.
So if this tool does not have this ID so if not ID then we're going to return as well because we don't
care about this tool.
Otherwise if it does have the ID then it is a drink object.
And we want to create a new drink object on the client in case we haven't already.
So that's where the drink class comes into play.
We can call the constructor, we can pass the guy.
And if you remember, the second one we have to pass would be the particular key for this drink.
But since we're going to be using the ID for this drink, I don't really care about this drink name
property.
So I can just pass an empty string.
Or in this case I'll just do child dot uh, name because I really want to pass the ID that is stored
for this object, because when we call this constructor, it's going to check whether or not it has
an ID, and if it does, then it's going to get an object from the server that has this particular ID.
And then inside of the dispense drink function.
What I actually want to do is I want to have the key or the drink name for this particular drink passed
to the function, as well as the properties for the function.
So when we actually call this function down here, I want to be able to pass the drink name and the
properties for the drink.
And then from this point, using those properties, what I'm going to do is I'm going to set the output
box dot text equal to the properties.
And we're going to get the dispense message.
So dot dispense message.
So that's going to be whatever the dispensed message is for that particular drink.
So if I go into pre-made drinks, if I got a cup of air, the dispense message would just be the default
of dispensing.
And then from this point I could do properties dot get the dispense sound and play that.
And then I'm going to wait for that dispense sound to end.
So dispense sound dot ended.
We'll wait for that event to fire.
And when it does then we can use the comms event and we can fire to the server to create a drink object.
And the drink object we want to create is going to be this particular key.
So the server will go create that drink object and add it to our backpack.
And when it gets added to our backpack then that's when this event down here gets fired and calls the
on child added to backpack.
And then from that point, once we've dispensed our drink, then we can close out the GUI.
So we dispense our drink and then once it gets dispensed and placed in our inventory, we can close
the GUI on our end.
All right.
Seems pretty good so far.
And in fact, since we're using this constant out of range here inside of our local script, I don't
think we actually need it to exist within.
Where was it?
Yeah, inside of our pre-made drinks module script.
We don't need it in here, so I'll just delete that.
And otherwise we're almost finished.
The last thing we need to do is set up our server script and make some drinks.
So I'll see you in the next lecture.